fig-financial-payments-b2b-xapi
Encrypting the Payment Payload
Introduction
Certain financial operations require additional security controls when transmitting sensitive customer and transaction data.
For that reason, the Payments API provides a dedicated encrypted submission endpoint.
Instead of sending the MB WAY payment details as a JSON body, your application must:
- Build the JSON object according to the contract
CreateMbWayIntentBackendRequest - Encrypt the JSON using AES-256/GCM
- Send:
- The ciphertext in the HTTP body
The IV (
X-IV) and AuthTag (X-AuthTag) in the headers- The X-Receipt-Token previously obtained from the provisional receipt flow
This ensures that sensitive customer data remains encrypted end-to-end.
How Encryption Works
When your system executes the insurance contracting process, the Financial Platform returns:
- receiptToken β an opaque token that must be returned unchanged when initiating the payment
- encryptionKey β a Base64-encoded AES-256 key used only for this payment flow
You will use this encryptionKey to encrypt the payment intent payload before submitting it to the encrypted endpoint.
Encryption Algorithm
The encryption process uses the following standards:
- AES-256 in GCM mode
- 12-byte IV (NIST recommendation for GCM)
- 128-bit authentication tag
- Base64 encoding for all encrypted components
GCM mode ensures both confidentiality and integrity (tamper detection).
What You Must Encrypt
The plaintext JSON must follow exactly the structure described in:
pay-lib.CreateMbWayIntentBackendRequest
This is the full MB WAY payment intent payload:
amount breakdown, payment key, customer details, vouchers, metadata, etc.
Only the transport changes β the JSON schema remains the same.
After building this JSON object, encrypt it and send only the Base64 ciphertext.
Request Structure for Encrypted Submission
Required HTTP Headers
| Header | Description |
|---|---|
X-Receipt-Token | Token provided during the provisional receipt process. Must be returned exactly as received. |
X-IV | Base64-encoded AES-GCM Initialization Vector used during encryption. |
X-AuthTag | Base64-encoded AES-GCM authentication tag generated during encryption. |
Idempotency-Key | UUID v4 ensuring safe retries without duplicated payments. |
Authorization | OAuth2 Client Credentials (Bearer token). |
HTTP Body
The entire body must be the Base64-encoded ciphertext produced by AES-GCM.
Example: BEm45DWVy4/7cVsrEgGP6XZGaCnZUcLotXgu70lXXFbeKSak1QMPKejnZ17yFgLmAJscuAf4o7Y=
No JSON wrapper or additional fields are allowed.
Java Example (Reference Implementation)
It demonstrates how to:
- Load the
encryptionKey - Build a valid JSON according to the schema
- Encrypt the JSON using AES-256/GCM
- Extract IV, AuthTag, and Ciphertext
- Map values to:
X-IVX-AuthTag- request body (ciphertext)
Below is an example implementation showing how to encrypt the MB WAY payment payload
before sending it to the encrypted endpoint /intents/mbway.
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class AesGcmEncryptor {
public static class EncryptionResult {
public String iv;
public String authTag;
public String ciphertext;
}
public static EncryptionResult encrypt(String plainText, String base64Key) throws Exception {
byte[] key = Base64.getDecoder().decode(base64Key);
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
// GCM requires a 12-byte IV (96 bits)
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// 128-bit authentication tag
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
// ciphertext + authTag are concatenated β split last 16 bytes
int tagLen = 16;
byte[] cipherBytes = new byte[encrypted.length - tagLen];
byte[] tagBytes = new byte[tagLen];
System.arraycopy(encrypted, 0, cipherBytes, 0, cipherBytes.length);
System.arraycopy(encrypted, cipherBytes.length, tagBytes, 0, tagLen);
EncryptionResult result = new EncryptionResult();
result.iv = Base64.getEncoder().encodeToString(iv);
result.authTag = Base64.getEncoder().encodeToString(tagBytes);
result.ciphertext = Base64.getEncoder().encodeToString(cipherBytes);
return result;
}
public static void main(String[] args) throws Exception {
// Encryption key provided by the provisionalReceipt response
String encryptionKey = "<BASE64_ENCRYPTION_KEY>";
// JSON payload properly escaped for Java string literal (must follow CreateMbWayIntentBackendRequest)
String payload = "{\n" +
" \"amount\": {\n" +
" \"gross\": {\n" +
" \"value\": \"513.6\",\n" +
" \"currency\": \"EUR\"\n" +
" },\n" +
" \"net\": {\n" +
" \"value\": \"513.6\",\n" +
" \"currency\": \"EUR\"\n" +
" }\n" +
" },\n" +
" \"paymentKey\": {\n" +
" \"phoneNumber\": \"916486353\",\n" +
" \"description\": \"Pagamentos de serviΓ§o Fidelidade\"\n" +
" },\n" +
" \"customer\": {\n" +
" \"fullName\": \"Maria Silva\",\n" +
" \"email\": \"maria.silva@example.com\",\n" +
" \"phoneNumber\": \"916486353\",\n" +
" \"fiscalNumber\": \"272353167\"\n" +
" },\n" +
" \"metadata\": {\n" +
" \"applicationId\": \"3b2c986c-882a-4298-b369-a20ff8ee3c79\"\n" +
" }\n" +
"}";
EncryptionResult enc = encrypt(payload, encryptionKey);
System.out.println("IV: " + enc.iv);
System.out.println("AuthTag: " + enc.authTag);
System.out.println("Ciphertext: " + enc.ciphertext);
}
}The logic can be replicated in any language supporting AES-GCM (Node.js, .NET, Python, Go, etc.).
Best Practices
- Always generate a new IV and AuthTag for every encryption operation.
- Do not attempt to read, modify, or decode the
X-Receipt-Token. - Validate your JSON against the schema before encrypting.
- Use the same
Idempotency-Keywhen retrying the exact same encrypted payload. - Never send plaintext payment data to the encrypted endpoint.